home *** CD-ROM | disk | FTP | other *** search
/ Computer Select (Limited Edition) / Computer Select.iso / dobbs / v17n05 / wincomm.exe / TERMINAL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-02  |  9.7 KB  |  346 lines

  1. ////////////////////////////////////////////////////////////////////////////
  2. //
  3. //    TERMINAL.C    - Written by Mike Sax for Dr. Dobb's Journal
  4. //
  5. //    This file implements a terminal window class "TERMINAL" which you can
  6. //    use to emulate a small tty terminal in a window.  If your application
  7. //    has windows of class "TERMINAL", you should call the InitTerminal
  8. //    function at the beginning of your program (not just for the first
  9. //    instance).
  10. //
  11. //    This file contains one public function:
  12. //
  13. //    BOOL InitTerminal(HANDLE hInstance);  // Return TRUE if success
  14. //
  15. //    To send characters to the terminal window, you can send a TW_SENDCHAR
  16. //    and TW_SENDSTRING messages.  For TW_SENDCHAR, the loword of lParam should
  17. //    contain the character you want to send to the terminal window.    For
  18. //    TW_SENDSTRING lParam should be a long pointer to a null-terminated
  19. //    character-string.
  20. ////////////////////////////////////////////////////////////////////////////
  21.  
  22. #include <windows.h>
  23. #include <string.h>
  24. #include "terminal.h"
  25.  
  26. // Exported functions:
  27. LONG FAR PASCAL _export TerminalWndProc(HANDLE hWnd, WORD wMessage,
  28.                                         WORD wParam, DWORD lParam);
  29.  
  30. // Static functions:
  31. void static InitFont(void);
  32. void static PositionCaret(HWND hWnd);
  33. void static SendChar(HWND hWnd, int nChar);
  34. int static Handle(WORD wParam, int nOldValue, int maxValue,
  35.                         int nTrackPosition);
  36.  
  37. // Global variables:
  38. static char *gszClass = "TERMINAL";
  39. static HFONT ghFont;    // Handle of terminal font
  40. static int gcxFont;     // Width of terminal font
  41. static int gcyFont;     // Height of terminal font
  42.  
  43. // Set "OEM-font" global variables: ghFont, gxFont, gyFont
  44. void static InitFont(void)
  45.     {
  46.  
  47.     HDC hDC;
  48.     TEXTMETRIC tm;
  49.  
  50.     ghFont = GetStockObject(OEM_FIXED_FONT);
  51.     hDC = GetDC(NULL);
  52.     SelectObject(hDC, ghFont);
  53.     GetTextMetrics(hDC, &tm);
  54.     ReleaseDC(NULL, hDC);
  55.     gcxFont = tm.tmMaxCharWidth;
  56.     gcyFont = tm.tmHeight;
  57.     }
  58.  
  59. // This function should be called once for every instance in your program
  60. // Return TRUE if success
  61. BOOL InitTerminal(HANDLE hInstance)
  62.     {
  63.     WNDCLASS wc;
  64.  
  65.     InitFont();
  66.     // If the terminal class was registered by a previous instance, we can
  67.     // return success
  68.     if (GetClassInfo(hInstance, gszClass, &wc))
  69.         return TRUE;
  70.     wc.style = 0;
  71.     wc.lpfnWndProc = TerminalWndProc;
  72.     wc.cbClsExtra = 0;
  73.     wc.cbWndExtra = sizeof(HTERMINAL);
  74.     wc.hInstance = hInstance;
  75.     wc.hIcon = NULL;
  76.     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  77.     wc.hbrBackground = GetStockObject(BLACK_BRUSH);
  78.     wc.lpszMenuName = NULL;
  79.     wc.lpszClassName = gszClass;
  80.     return RegisterClass(&wc);
  81.     }
  82.  
  83. // Position the caret in the window IMPORTANT: This function should only be
  84. // called when the window has the input focus!
  85. void static PositionCaret(HWND hWnd)
  86.     {
  87.     HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
  88.     NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
  89.  
  90.     if (NULL == npTerminal)
  91.         return;     // Abort function
  92.     SetCaretPos(gcxFont * (npTerminal->xCursor - npTerminal->xOffset),
  93.                 gcyFont * (npTerminal->yCursor - npTerminal->yOffset + 1) - 1);
  94.     LocalUnlock(hTerminal);
  95.     }
  96.  
  97. // Send a character to a terminal window (internal function)
  98. void static SendChar(HWND hWnd, int nChar)
  99.     {
  100.     HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
  101.     NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
  102.  
  103.     if (NULL == npTerminal)
  104.         return;                // Abort function
  105.     switch(nChar)
  106.         {
  107.         case '\t':            // Tab
  108.             npTerminal->xCursor += TABSIZE - (npTerminal->xCursor % TABSIZE);
  109.             break;
  110.         case '\r':            // Return
  111.             npTerminal->xCursor = 0;
  112.             break;
  113.         case '\n':            // New line
  114.             npTerminal->yCursor++;
  115.             break;
  116.         case '\a':            // Beep
  117.             MessageBeep(0);
  118.             break;
  119.         case '\xC':         // Clear screen
  120.             memset(npTerminal->achBuffer[0], ' ', ROWS * COLUMNS);
  121.             npTerminal->xCursor = npTerminal->yCursor = 0;
  122.             InvalidateRect(hWnd, NULL, TRUE);
  123.             break;
  124.         case '\b':            // Backspace
  125.             if (npTerminal->xCursor)
  126.                 npTerminal->xCursor--;
  127.             break;
  128.         default:
  129.             {
  130.             HDC hDC;
  131.             npTerminal->achBuffer[npTerminal->yCursor]
  132.                                 [npTerminal->xCursor] = (char)nChar;
  133.  
  134.             if (hDC = GetDC(hWnd))
  135.                 {
  136.                 SelectObject(hDC, ghFont);
  137.                 SetBkColor(hDC, 0l);
  138.                 SetTextColor(hDC, RGB(255, 128, 128));
  139.                 HideCaret(hWnd);    // Don't paint over the caret
  140.                 TextOut(hDC,
  141.                         gcxFont * (npTerminal->xCursor - npTerminal->xOffset),
  142.                         gcyFont * (npTerminal->yCursor - npTerminal->yOffset),
  143.                         (LPSTR)&nChar, 1);
  144.                 ShowCaret(hWnd);
  145.                 ReleaseDC(hWnd, hDC);
  146.                 }
  147.  
  148.             npTerminal->xCursor++;
  149.             }
  150.         }
  151.     if (npTerminal->xCursor >= COLUMNS)
  152.         {
  153.         npTerminal->xCursor = 0;
  154.         npTerminal->yCursor++;
  155.         }
  156.     if (npTerminal->yCursor >= ROWS)
  157.         {
  158.         npTerminal->yCursor = ROWS - 1;
  159.         memmove(npTerminal->achBuffer[0], npTerminal->achBuffer[1],
  160.                 (ROWS - 1) * COLUMNS);
  161.         memset(npTerminal->achBuffer[ROWS - 1], ' ', COLUMNS);
  162.         ScrollWindow(hWnd, 0, -gcyFont, NULL, NULL);
  163.         UpdateWindow(hWnd);                 // Send WM_PAINT message now
  164.         }
  165.     if (hWnd == GetFocus())
  166.         PositionCaret(hWnd);
  167.     LocalUnlock(hTerminal);
  168.     }
  169.  
  170. // Handle WM_VSCROLL or WM_HSCROLL message.
  171. // Returns the new scrollbar position
  172. int static HandleScroll(WORD wParam, int nOldValue, int maxValue,
  173.                         int nTrackPosition)
  174.     {
  175.     int nNewValue = nOldValue;
  176.  
  177.     switch(wParam)
  178.         {
  179.         case SB_BOTTOM:
  180.             nNewValue = maxValue - 1;
  181.             break;
  182.         case SB_LINEUP:
  183.             --nNewValue;
  184.             break;
  185.         case SB_LINEDOWN:
  186.             ++nNewValue;
  187.             break;
  188.         case SB_PAGEUP:
  189.             nNewValue -= maxValue / 5;
  190.             break;
  191.         case SB_PAGEDOWN:
  192.             nNewValue += maxValue / 5;
  193.             break;
  194.         case SB_TOP:
  195.             nNewValue = 0;
  196.         case SB_THUMBPOSITION:
  197.             nNewValue = nTrackPosition;
  198.             break;
  199.         }
  200.     if (nNewValue < 0)
  201.         nNewValue = 0;
  202.     if (nNewValue > maxValue)
  203.         nNewValue = maxValue;
  204.     return nNewValue;
  205.     }
  206.  
  207. // This is the window function of the terminal class
  208. LONG FAR PASCAL _export TerminalWndProc(HANDLE hWnd, WORD wMessage,
  209.                                         WORD wParam, DWORD lParam)
  210.     {
  211.  
  212.     switch(wMessage)
  213.         {
  214.         case WM_CREATE:
  215.             {
  216.             HTERMINAL hTerminal = LocalAlloc(LHND, sizeof(TERMINAL));
  217.             NPTERMINAL npTerminal;
  218.  
  219.             if (!hTerminal)
  220.                 return -1;        // Fail CreateWindow
  221.             npTerminal = (NPTERMINAL)LocalLock(hTerminal);
  222.             if (npTerminal == NULL)
  223.                 {
  224.                 LocalFree(hTerminal);
  225.                 return -1;
  226.                 }
  227.             memset((PSTR)npTerminal->achBuffer, ' ', ROWS * COLUMNS);
  228.             SetWindowWord(hWnd, 0, (WORD)hTerminal);
  229.             LocalUnlock(hTerminal);
  230.             }
  231.             break;
  232.         case WM_HSCROLL:
  233.             {
  234.             HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
  235.             NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
  236.             int xNewOffset;
  237.  
  238.             if (NULL == npTerminal)
  239.                 return 0l;    // abort
  240.             xNewOffset = HandleScroll(wParam, npTerminal->xOffset,
  241.                     max(0, COLUMNS - npTerminal->cxWindow), LOWORD(lParam));
  242.             if (xNewOffset != npTerminal->xOffset)
  243.                 {
  244.                 ScrollWindow(hWnd, gcxFont * (npTerminal->xOffset -
  245.                              xNewOffset), 0, NULL, NULL);
  246.                 npTerminal->xOffset = xNewOffset;
  247.                 SetScrollPos(hWnd, SB_HORZ, xNewOffset, TRUE);
  248.                 }
  249.             LocalUnlock(hTerminal);
  250.             }
  251.             break;
  252.         case WM_VSCROLL:
  253.             {
  254.             HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
  255.             NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
  256.             int yNewOffset;
  257.  
  258.             if (NULL == npTerminal)
  259.                 return 0l;    // abort
  260.             yNewOffset = HandleScroll(wParam, npTerminal->yOffset,
  261.                 max(0, ROWS - npTerminal->cyWindow), LOWORD(lParam));
  262.             if (yNewOffset != npTerminal->yOffset)
  263.                 {
  264.                 ScrollWindow(hWnd, 0, gcyFont * (npTerminal->yOffset -
  265.                              yNewOffset),  NULL, NULL);
  266.                 npTerminal->yOffset = yNewOffset;
  267.                 SetScrollPos(hWnd, SB_VERT, yNewOffset, TRUE);
  268.                 }
  269.             LocalUnlock(hTerminal);
  270.             }
  271.             break;
  272.         case WM_DESTROY:
  273.             LocalFree(GetWindowWord(hWnd, 0));
  274.             break;
  275.         case WM_PAINT:
  276.             {
  277.             int i;
  278.             PAINTSTRUCT ps;
  279.             HDC hDC;
  280.             HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
  281.             NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
  282.  
  283.             if (NULL == npTerminal)
  284.                 return 0l;        // Can't access our parameters->abort paint
  285.             hDC = BeginPaint(hWnd, &ps);
  286.             SelectObject(hDC, ghFont);
  287.             SetBkColor(hDC, 0l);
  288.             SetTextColor(hDC, RGB(255, 128, 128));
  289.             for(i = 0 ; i < ROWS ; ++i)
  290.                 TextOut(hDC, - (npTerminal->xOffset * gcxFont),
  291.                         gcyFont * (i - npTerminal->yOffset),
  292.                         npTerminal->achBuffer[i], COLUMNS);
  293.             EndPaint(hWnd, &ps);
  294.             LocalUnlock(hTerminal);
  295.             }
  296.             break;
  297.         case WM_SIZE:
  298.             {
  299.             HTERMINAL hTerminal = GetWindowWord(hWnd, 0);
  300.             NPTERMINAL npTerminal = (NPTERMINAL)LocalLock(hTerminal);
  301.             RECT rect;
  302.  
  303.             if (NULL == npTerminal)
  304.                 return 0l;
  305.             // Get client dimensions without scroll bars (we have no border)
  306.             GetWindowRect(hWnd, &rect);
  307.             // Set max rows and columns that can be displayed
  308.             npTerminal->cxWindow = (rect.right - rect.left) / gcxFont;
  309.             npTerminal->cyWindow = (rect.bottom - rect.top) / gcyFont;
  310.             SetScrollRange(hWnd, SB_HORZ, 0,
  311.                            max(0, COLUMNS - npTerminal->cxWindow), TRUE);
  312.             SetScrollRange(hWnd, SB_VERT, 0,
  313.                            max(0, ROWS - npTerminal->cyWindow), TRUE);
  314.             LocalUnlock(hTerminal);
  315.             }
  316.             break;
  317.         case TW_SENDCHAR:
  318.             SendChar(hWnd, wParam);
  319.             break;
  320.         case TW_SENDSTRING:
  321.             while ((LPSTR)(lParam))
  322.                 SendChar(hWnd, *((LPSTR)(lParam++)));
  323.             break;
  324.         case WM_CHAR:
  325.             // Send a notification message to our parent
  326.             SendMessage(GetParent(hWnd), WM_COMMAND,
  327.                         GetWindowWord(hWnd, GWW_ID), MAKELONG(hWnd, wParam));
  328.             break;
  329.         case WM_LBUTTONDOWN:
  330.             SetFocus(hWnd);
  331.         case WM_SETFOCUS:
  332.             CreateCaret(hWnd, NULL, gcxFont, 0);
  333.             PositionCaret(hWnd);
  334.             ShowCaret(hWnd);
  335.             break;
  336.         case WM_KILLFOCUS:
  337.             DestroyCaret();
  338.             break;
  339.         case WM_GETDLGCODE:
  340.             return DLGC_WANTALLKEYS;    // We also process enter, tab, ...
  341.         default:
  342.             return DefWindowProc(hWnd, wMessage, wParam, lParam);
  343.         }
  344.     return 0l;
  345.     }
  346.